﻿$.fn.dropdown = function(options) {
    var defaults = {
        highlightClass: 'ui-dropdown-highlight',
        displayArrow: true
    };

    var opt = $.extend({}, defaults, options);
    if (typeof (opt.dropDowns) == 'undefined')
        throw "You have not defined drop down(s)";
    if (typeof (opt.dropDowns) == 'string')
        opt.dropDowns = $(opt.dropDowns);
    opt.dropDowns
        .hide()
        .live('mousemove', function() { $(this).stop(true, false); })
        .live('mouseout', function() {
            $(this).animate({ duration: 200 }, { step: function() { }, complete: function() {
                $(this).data('source').removeClass(opt.highlightClass);
                $(this).hide();
                if (opt.displayArrow)
                    $('#dropdown_arrow', $(this).data('source')).remove();
            }
            })
        });
    this.live('mouseover', function() {
        var jq = $(this);
        $(this).data('target').stop(true, false).data('source', jq);
        if ($('#dropdown_arrow', jq).length == 0) {
            jq.addClass(opt.highlightClass);
            jq.prepend($('<div id="dropdown_arrow" class="' + opt.highlightClass + '" style="border-top:none;border-right:none;border-bottom:none;float:right;text-align:center;background-color:#9999FF;"><div style="width:0px;height:0px; border-left:solid #9999FF 3px;border-right:solid #9999FF 3px;border-top:solid black 3px "></div></div>'));
            $('#dropdown_arrow', jq).height(jq.innerHeight()).width(jq.innerHeight()).children("div").css({ 'margin-top': 3 * jq.innerHeight() / 8, 'border-top-width': jq.innerHeight() / 4, 'border-left-width': jq.innerHeight() / 4, 'border-right-width': jq.innerHeight() / 4 });
        }
    })
    .live('mouseout', function() {
        $(this).data('target').animate({ duration: 200 }, { step: function() { }, complete: function() {
            var source = $(this).data('source');
            source.removeClass(opt.highlightClass);
            $(this).hide();
            $('#dropdown_arrow', source).remove();
        }
        });
    });
    if (opt.dropDowns.length && opt.dropDowns.length == this.length && opt.dropDowns.length != 1)
        this.each(function(index) {
            var element = this;
            opt.dropDowns.each(function(i) {
                if (index == i) {
                    $(element).data('target', this).bind('click', function() {
                        $(this).show();
                    });
                }
            })
        });
    else
        $(this).data('target', $(opt.dropDowns[0])).bind('click', function() { $(this).data('target').show(); });
}

$.fn.cascade = function(options) {
    var defaults = {
        useLiveQuery: true,
        useWebService: false,
        webServiceUrl: null,
        webServiceMethod: "GetElements",
        getValues: null,
        classPrefix: "sub_",
        addDefaultOption: true,
        defaultValue: "",
        defaultText: "-- Select an option --",
        focusTarget: true
    };
    var opt = $.extend({}, defaults, options);
    if (!opt.parentDropDowns)
        throw "A parent drop down should be specified";
    if (typeof (opt.parentDropDowns) == 'string')
        opt.parentDropDowns = $(opt.parentDropDowns);
    var targets = this;
    var getValuesFromWebService = function() {
        $.ajax({
            type: "POST",
            contentType: "application/json; charset=utf-8",
            url: opt.webServiceUrl + "/" + opt.webServiceMethod,
            data: "{ selectedValue:" + $(this).val() + " }",
            dataType: "json",
            complete: function(data) {
                if (typeof (data) == 'string')
                    data = eval(data);
                targets.empty();
                if (opt.addDefaultOption)
                    targets.append('<option value="' + opt.defaultValue + '">' + opt.defaultText + '</option>');
                $.each(data, function(key, value) {
                    targets.append('<option value="' + key + '">' + value + '</option>');
                });
                if (opt.focusTarget)
                    targets.focus();
            }
        });
    }
    var getValuesFromClass = function() {
        targets.each(function() {
            if (!$(this).data('items')) {
                $(this).data('items', $.map($('option'), function(element) {
                    return { className: element.className, key: element.value, value: $(element).text() };
                }))
            }
        });
        $('option', targets).remove();
        var selectedValue = $(this).val();
        targets.empty()
        if (opt.addDefaultOption)
            targets.append('<option value="' + opt.defaultValue + '">' + opt.defaultText + '</option>');
        targets.each(function() {
            var target = $(this);
            var selectOptions = $.grep(target.data('items'), function(element) { return element.className == opt.classPrefix + selectedValue });
            $.each(selectOptions, function() {
                target.append('<option value="' + this.key + '">' + this.value + '</option>');
            })
        })
        targets.val(0);
        targets.change();
        if (opt.focusTarget)
            targets.focus();
    };
    if (!opt.getValues) {
        if (opt.useWebService)
            opt.getValues = getValuesFromWebService;
        else
            opt.getValues = getValuesFromClass;
    }

    if (opt.useLiveQuery)
        opt.parentDropDowns.bind('change', opt.getValues);
    else
        opt.parentDropDowns.live('change', opt.getValues);
    opt.parentDropDowns.change();
}

$.fn.listSelector = function(options) {
    var defaults = { validationFunction: null, validatorSelector: '.validate', useLiveQuery: true, tokenSeparator: ';', validateTokensSeparately: true };

    function caretPosition(ctrl, caretPos, selectFromLastPosition) {
        if (typeof (caretPos) != 'undefined')
            setCaretPosition(ctrl, caretPos, selectFromLastPosition);
        else
            return getCaretPosition(ctrl);
    }

    function getCaretPosition(ctrl) {
        var CaretPos = 0;
        // IE Support
        if (document.selection) {

            ctrl.focus();
            var Sel = document.selection.createRange();
            var SelLength = document.selection.createRange().text.length;
            Sel.moveStart('character', -ctrl.value.length);
            CaretPos = Sel.text.length - SelLength;
        }
        // Firefox support
        else if (ctrl.selectionStart || ctrl.selectionStart == '0')
            CaretPos = ctrl.selectionStart;

        return (CaretPos);
    }
    function selectionLength(ctrl, length) {
        if (typeof (length) == 'undefined') {
            ctrl.focus();
            return document.selection.createRange().text.length;
        }
        else {
            var oSel = document.selection.createRange();
            oSel.moveEnd('character', length);
            oSel.select();
        }
    }

    function setCaretPosition(ctrl, iCaretPos, selectFromLastPosition) {

        // IE Support
        if (document.selection) {

            // Set focus on the element
            ctrl.focus();

            // Create empty selection range
            var caret = caretPosition(ctrl);
            var oSel = document.selection.createRange();

            // Move selection start and end to 0 position
            oSel.moveEnd('character', -ctrl.value.length);

            // Move selection start and end to desired position
            if (selectFromLastPosition) {
                if (caret > iCaretPos) {
                    oSel.moveStart('character', iCaretPos);
                    oSel.moveEnd('character', caret);
                }
                else {
                    oSel.moveStart('character', caret);
                    oSel.moveEnd('character', iCaretPos);
                }
            }
            else {
                oSel.moveStart('character', iCaretPos);
            }


            oSel.select();
        }

        // Firefox support
        else if (ctrl.selectionStart || ctrl.selectionStart == '0') {
            ctrl.selectionStart = iCaretPos;
            ctrl.selectionEnd = iCaretPos;
            ctrl.focus();
        }
    }

    var opt = $.extend({}, defaults, options);

    if (typeof (opt.validatorSelector) == 'string')
        opt.validatorSelector = $(opt.validatorSelector);

    if (this.length == opt.validatorSelector.length && this.length == 1) {
        opt.validatorSelector.data('source', $(this[0]));
    }

    var listSelectors = this;


    var validate = function(index) {
        if (index < $('li', listSelectors).length)
            return;
        var key = opt.validationFunction($.trim(this));
        if (key != null) {
            if (index > 0)
                $('ul', listSelectors).append('<li style="float:left">;&nbsp;</li>');
            $('ul', listSelectors).append('<li style="float:left" key="' + key + '">' + this + '</li>');
        }
    }

    if (opt.useLiveQuery)
        opt.validatorSelector.live('click', function() { var value = $('input[type=text]', $(this).data('source')).val(); $.each(value.split(opt.tokenSeparator), validate); });
    else
        opt.validatorSelector.bind('click', function() { });

    if (this.children('ul').length == 0)
        this.append('<ul>');


    var dummyInput = $('input[type=text]', this)[0];
    $('ul', this).css({ 'position': 'absolute', 'overflow': 'hidden', 'z-index': '10', 'list-style': 'none', 'margin': 0, 'padding': 3, 'font-family': $('input[type=text]', this).css('font-family'), 'font-size': $('input[type=text]', this).css('font-size'), 'font-weight': $('input[type=text]', this).css('font-weight') });
    $('li', this).css({ 'float': 'left' }).live('click', function() {
        $('input[type=text]', dummyInput).trigger('click', arguments);
        var caret = caretPosition(dummyInput);
        var currentLi = this;
        var totalLength = 0;
        $('li', listSelectors).each(function() {
            var value = $.trim($(this).text());
            if (currentLi == this) {
                if (this.key) {
                    caretPosition(dummyInput, totalLength);
                    selectionLength(dummyInput, value.length);
                }
                else
                    caretPosition(dummyInput, caret);
            }
            totalLength += value.length;
        });
    });
    $('input[type=text]', this).live('keydown', function(event) {
        if (!event)
            event = window.event;
        if (event) {
            if (event.keyCode)
                keyCode = event.keyCode;
            if (event.which)
                keyCode = event.which;
        }
        var dummyInput = $('input[type=text]', listSelectors);
        var propagateEvent = true;
        var caretPos = caretPosition(this);
        var totalLength = 0;
        //Left
        if (keyCode == 37) {
            $('li', listSelectors).each(function() {
                var value = $.trim($(this).text());
                if (totalLength < caretPos && value.length + totalLength > caretPos - 1) {
                    var inputValue = dummyInput.val();
                    if (this.key) {
                        caretPosition(dummyInput[0], caretPos - value.length, !event.ctrlKey);
                        propagateEvent = value == 1;
                    }
                }
                totalLength += value.length;
            });

            return propagateEvent;
        }
        //Right
        if (keyCode == 39) {
            $('li', listSelectors).each(function() {
                var value = $.trim($(this).text());
                if (totalLength < caretPos + 1 && value.length + totalLength > caretPos) {
                    var inputValue = dummyInput.val();
                    if (this.key) {
                        if (!(propagateEvent = selectionLength(dummyInput[0]) > 0))
                            caretPosition(dummyInput[0], caretPos + value.length, !event.ctrlKey);
                    }
                }
                totalLength += value.length;
            });

            return propagateEvent;
        }
        //BackSpace
        if (keyCode == 8) {
            $('li', listSelectors).each(function() {
                var value = $.trim($(this).text());
                var selLength = selectionLength(dummyInput[0]);
                if (totalLength < caretPos + selLength && value.length + totalLength > caretPos + selLength - 1) {
                    var inputValue = dummyInput.val();
                    if (this.key || value == 1) {
                        if (selLength == 0) {
                            dummyInput.val(inputValue.substring(0, totalLength) + inputValue.substring(totalLength + value.length));
                        }
                        else {
                            dummyInput.val(inputValue.substring(0, caretPos) + inputValue.substring(caretPos + selLength));
                            caretPosition(dummyInput[0], caretPos);
                        }
                        $(this).remove();
                        propagateEvent = value == 1;
                    }
                    else {
                        $(this).text(value.substring(0, caretPos - totalLength - 1) + value.substring(caretPos - totalLength));
                    }
                }
                totalLength += value.length;
            });
            this.focus();
            return propagateEvent;
        }
    });

}

$.fn.tooltip = function(options) {
    var opt = $.extend({}, $.fn.tooltip.defaults, options);
    if (typeof (opt.tooltipSelector) == 'string')
        opt.tooltipSelector = $(opt.tooltipSelector);
    opt.tooltipSelector
        .live('mousemove', function() { showIfViewable($(this)); })
        .live('mouseout', function() { $.fn.tooltip.hide($(this)); })
        .hide().fadeTo(0, 0);
    this
        .live('mouseover', function() {
            var rssItem = $(this).parents(opt.parentRelativeSelector).get(0);
            showIfViewable($(opt.tooltipSelector.selector, rssItem).css('position', 'absolute'), $(this), opt.tooltipAlignment);
        })
        .live('mouseout', function(e) {
            var rssItem = $(this).parents(opt.parentRelativeSelector).get(0);
            $.fn.tooltip.hide($(opt.tooltipSelector.selector, rssItem));
        });


    function showIfViewable(tooltip, relative, alignments) {
        var defaultalignments = { parent: { horizontal: 'center', vertical: 'bottom' }, child: { horizontal: 'center', vertical: 'top'} };
        alignments = $.extend({}, defaultalignments, alignments);
        if (relative) {
            tooltip.positionTo({ parentSelector: relative, parentAlignment: [alignments.parent.horizontal, alignments.parent.vertical], childAlignment: [alignments.child.horizontal, alignments.child.vertical] });
        }
        if (!$.fn.tooltip.show(tooltip).visible() && relative) {
            var tooltipBounds = $.bounds(tooltip);
            var relativeBounds = $.bounds(relative);
            if (tooltipBounds.left() < 0) {
                alignments.parent.horizontal = 'right';
                alignments.child.horizontal = 'left';
                alignments.parent.vertical = 'top';
                alignments.child.vertical = 'top';
            }
            if (tooltipBounds.top() < 0) {
                alignments.parent.vertical = 'bottom';
                alignments.child.vertical = 'top';
                alignments.parent.horizontal = 'right';
                alignments.child.horizontal = 'left';
            }
            if (relativeBounds.right() + tooltipBounds.width() >= $.windowSize().width && relativeBounds.bottom() + tooltipBounds.height() >= $.windowSize().height) {
                alignments.parent.vertical = 'bottom';
                alignments.child.vertical = 'bottom';
                alignments.parent.horizontal = 'left';
                alignments.child.horizontal = 'right';
            }
            else if (relativeBounds.right() + tooltipBounds.width() >= $.windowSize().width) {
                alignments.parent.horizontal = 'left';
                alignments.child.horizontal = 'right';
                alignments.parent.vertical = 'top';
                alignments.child.vertical = 'top';
            }
            else if (relativeBounds.bottom() + tooltipBounds.height() >= $.windowSize().height) {
                alignments.parent.vertical = 'bottom';
                alignments.child.vertical = 'bottom';
                alignments.parent.horizontal = 'right';
                alignments.child.horizontal = 'left';
            }

            tooltip.positionTo({ parentSelector: relative, parentAlignment: [alignments.parent.horizontal, alignments.parent.vertical], childAlignment: [alignments.child.horizontal, alignments.child.vertical] });
            var relativeBounds_new = $.bounds(relative);

            //If the scroolbar has disappeared, reapply positionning
            if (relativeBounds.top() != relativeBounds_new.top() || relativeBounds.bottom() != relativeBounds_new.bottom() || relativeBounds.left() != relativeBounds_new.left() || relativeBounds.right() != relativeBounds_new.right())
                tooltip.positionTo({ parentSelector: relative, parentAlignment: [alignments.parent.horizontal, alignments.parent.vertical], childAlignment: [alignments.child.horizontal, alignments.child.vertical] });
        }
    }
}

$.fn.tooltip.show = function(tooltip) {
    return tooltip.stop(true, false).css('display', 'block').fadeTo("normal", 1);
}

$.fn.tooltip.hide = function(tooltip) {
    return tooltip.fadeTo("normal", 0, function() { $(this).css('display', 'none') });
}

$.fn.tooltip.defaults = { relativeSelector: true, tooltipSelector: '.tooltip', parentRelativeSelector: 'td' };

$.fn.positionTo = function(options) {
    var opt = $.extend({}, $.fn.positionTo.defaults, options);
    if (!opt.parentSelector && !opt.childSelector)
        throw "At least one child should be specified";
    if (opt.parentSelector) {
        if (typeof (opt.parentSelector) == 'string')
            opt.parentSelector = $(opt.parentSelector);
        var children = this;
        if (opt.parentSelector.length == this.length && this.length != 1) {

        }
        else {
            var parentBounds = $.bounds($(opt.parentSelector[0]));
            children.css('position', 'absolute');
            //Deals with horizontals
            $.each(opt.parentAlignment, function() {
                var parentHorizontalAlignment = this;
                $.each(opt.childAlignment, function() {
                    if (this == "left") {
                        if (parentHorizontalAlignment == "left")
                            children.css('left', parentBounds.left());
                        if (parentHorizontalAlignment == "center")
                            children.css('left', parentBounds.left() + parentBounds.width() / 2);
                        if (parentHorizontalAlignment == "right")
                            children.css('left', parentBounds.right());
                    }
                    if (this == "center") {
                        if (parentHorizontalAlignment == "left")
                            children.css('left', parentBounds.left() - children.width() / 2);
                        if (parentHorizontalAlignment == "center")
                            children.css('left', parentBounds.left() + parentBounds.width() / 2 - children.width() / 2);
                        if (parentHorizontalAlignment == "right")
                            children.css('left', parentBounds.right() - children.width() / 2);
                    }
                    if (this == "right") {
                        if (parentHorizontalAlignment == "left")
                            children.css('left', parentBounds.left() - children.width());
                        if (parentHorizontalAlignment == "center")
                            children.css('left', parentBounds.left() + parentBounds.width() / 2 - children.width() / 2);
                        if (parentHorizontalAlignment == "right")
                            children.css('left', parentBounds.right() - children.width());
                    }

                });
            });

            //Deals with verticals
            $.each(opt.parentAlignment, function() {
                var parentVerticalAlignment = this;
                $.each(opt.childAlignment, function() {
                    if (this == "top") {
                        if (parentVerticalAlignment == "top")
                            children.css('top', parentBounds.top());
                        if (parentVerticalAlignment == "middle")
                            children.css('top', parentBounds.top() + parentBounds.height() / 2);
                        if (parentVerticalAlignment == "bottom")
                            children.css('top', parentBounds.bottom());
                    }
                    if (this == "middle") {
                        if (parentVerticalAlignment == "top")
                            children.css('top', parentBounds.top() - children.height() / 2);
                        if (parentVerticalAlignment == "middle")
                            children.css('top', parentBounds.top() + parentBounds.height() / 2 - children.height() / 2);
                        if (parentVerticalAlignment == "bottom")
                            children.css('top', parentBounds.bottom() - children.width() / 2);
                    }
                    if (this == "bottom") {
                        if (parentVerticalAlignment == "top")
                            children.css('top', parentBounds.top() - children.height());
                        if (parentVerticalAlignment == "middle")
                            children.css('top', parentBounds.top() + parentBounds.height() / 2 - children.height());
                        if (parentVerticalAlignment == "bottom")
                            children.css('top', parentBounds.bottom() - children.height());
                    }
                });
            });

            children.trigger('positioned', { parent: opt.parentAlignment, child: opt.childAlignment });

        }
    }
    if (opt.childSelector) {
        if (typeof (opt.childSelector) == 'string')
            opt.childSelector = $(opt.childSelector);
    }
}

$.fn.positionTo.defaults = { parentAlignment: ['bottom', 'left'], childAlignment: ['top', 'left'] }
$.fn.positionTo.horizontals = ['left', 'center', 'right'];
$.fn.positionTo.verticals = ['top', 'middle', 'bottom'];

function findPos(obj) {
    var curleft = obj.offsetLeft || 0;
    var curtop = obj.offsetTop || 0;
    while (obj = obj.offsetParent) {
        curleft += obj.offsetLeft
        curtop += obj.offsetTop
    }
    return { x: curleft, y: curtop };
}

$.extend({ windowSize: function() {
    var myWidth = 0, myHeight = 0;
    if (typeof (window.innerWidth) == 'number') {
        //Non-IE
        myWidth = window.innerWidth;
        myHeight = window.innerHeight;
    } else if (document.documentElement && (document.documentElement.clientWidth || document.documentElement.clientHeight)) {
        //IE 6+ in 'standards compliant mode'
        myWidth = document.documentElement.clientWidth;
        myHeight = document.documentElement.clientHeight;
    } else if (document.body && (document.body.clientWidth || document.body.clientHeight)) {
        //IE 4 compatible
        myWidth = document.body.clientWidth;
        myHeight = document.body.clientHeight;
    }
    return { height: myHeight, width: myWidth };
}, bounds: function(position, size) {
    if (position.jquery)
        return $.bounds(position.position(), { 'height': position.height(), 'width': position.width() });
    return {
        position: position,
        size: size,
        height: function() { return size.height; },
        width: function() { return size.width },
        top: function() { return position.top },
        left: function() { return position.left },
        bottom: function() { return this.top() + this.height() },
        right: function() { return this.left() + this.width() },
        In: function(bound) {
            return this.left() > bound.left() &&
                this.top() > bound.top() &&
                this.right() < bound.right() &&
                this.bottom() < bound.bottom();
        }
    }
}
});

$.fn.visible = function(rect) {
    var result = true;
    if (!rect)
        rect = $.fn.visible.defaults;
    this.each(function() {
        if (!result)
            return;
        var size = { height: $(this).height(), width: $(this).width() };
        var position = $(this).position();
        var offset = $(this).offset();
        position.left += offset.left;
        position.top += offset.top;
        var bounds = $.bounds(position, size)
        return result = bounds.In(rect);
    })
    return result;
}
$.fn.visible.defaults = $.bounds({ top: 0, left: 0 }, { width: $.windowSize().width, height: $.windowSize().height });